/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at https://curl.se/docs/copyright.html.
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ***************************************************************************/
/* <DESC>
 * Use the progress callbacks, old and/or new one depending on available
 * libcurl version.
 * </DESC>
 */
#include <stdio.h>
#include <curl/curl.h>
 
#if LIBCURL_VERSION_NUM >= 0x073d00
/* In libcurl 7.61.0, support was added for extracting the time in plain
   microseconds. Older libcurl versions are stuck in using 'double' for this
   information so we complicate this example a bit by supporting either
   approach. */
#define TIME_IN_US 1 /* microseconds */
#define TIMETYPE curl_off_t
#define TIMEOPT CURLINFO_TOTAL_TIME_T
#define MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL     3000000
#else
#define TIMETYPE double
#define TIMEOPT CURLINFO_TOTAL_TIME
#define MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL     3
#endif
 
#define STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES         6000
 
struct myprogress {
  TIMETYPE lastruntime; /* type depends on version, see above */
  CURL *curl;
};
	
/* this is how the CURLOPT_XFERINFOFUNCTION callback works */
static int xferinfo(void* ptr, curl_off_t TotalToDownload, curl_off_t NowDownloaded, 
                    curl_off_t TotalToUpload, curl_off_t NowUploaded)
{
    if (TotalToDownload <= 0.0) {
        return 0;
    }

	static int old_download = 0;
	static double old_time = 0;

	struct timeval start; 
    gettimeofday(&(start), NULL); 
    double start_ms = 1.0*start.tv_sec+1.0*start.tv_usec/1000000;
	
	double speed = 0;
	if(old_download)
	{
		speed = (double)(NowDownloaded-old_download)/(start_ms-old_time);
	}
	
	old_time = start_ms;
	old_download = NowDownloaded;
	static double fractiondownloaded = 0;
	fractiondownloaded = 100.0*NowDownloaded / TotalToDownload;
	static double old_fraction = 0;
	if( speed && (fractiondownloaded-old_fraction>=1 || NowDownloaded == TotalToDownload))
	{
		printf("NowDownloaded = %d\t\tTotalToDownload = %d\t\t",NowDownloaded, TotalToDownload);
		// create the "meter"
		printf("%3.0lf%%",fractiondownloaded);
		printf("%20d MB/s\r",(int)speed/1000000);
		old_fraction = fractiondownloaded;
		fflush(stdout);
	}
	if(NowDownloaded == TotalToDownload)
		printf("\n");
    // if you don't return 0, the transfer will be aborted - see the documentation
    return 0; 
}
 
int main(void)
{
  CURL *curl;
  CURLcode res = CURLE_OK;
  struct myprogress prog;
 
  curl = curl_easy_init();
  if(curl) {
    prog.lastruntime = 0;
    prog.curl = curl;
 
//    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_URL, "www.baidu.com");
 
	FILE *outfile;
	outfile = fopen("./test.img", "wb");
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile);
 
    curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo);
    /* pass the struct pointer into the xferinfo function, note that this is
       an alias to CURLOPT_PROGRESSDATA */
    curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &prog);

    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
    res = curl_easy_perform(curl);
 
    if(res != CURLE_OK)
      fprintf(stderr, "%s\n", curl_easy_strerror(res));
 
    /* always cleanup */
    curl_easy_cleanup(curl);
	fclose(outfile);
  }
  return (int)res;
}